/* Includes -----------------------------------------------------*/
#include <string.h>
#include "gkt_debug.h"
#include "gkt_fps.h" 
#include "gkt_rtc.h"
#include "gkt_user.h"
#include "gkt_card.h"
#include "gkt_door.h"
#include "gkt_record_unlock.h"
#include "gkt_network.h"
#include "gkt_driver.h"
#include "window_common.h"
#include "window_verify.h"
#include "window_trial.h"
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
#include "gkt_face_id.h"
#include "gkt_os.h"
#endif
#if	defined(GKT_CONFIG_PROXIMITY_SENSOR_ENABLE) && (GKT_CONFIG_PROXIMITY_SENSOR_ENABLE)
#include "gkt_pr_sensor.h"
#endif

/************************************************************
* BPK Key:A total of 32 Uint32_t 
*		  uint32_t [0]:description:gkt_retmem.h
*
*         uint32_t [1]:			   
*			   Byte[0]:door tamper used 
*					--io1  :door tamper detect level
*			   		--io1~2:door tamper gpio io number
*              Byte[1]:door lock used
*					Record door lock status
*			   Byte[2]:Record always open enabled
*
*         uint32_t [2~3]:description:gkt_retmem.h
*			 
*		  uint32_t [4]:window_retmem_data
*			   record verify failed counts
*
*		  uint32_t [5]:window_retmem_data
*              record verify failed expire dtu
*
*		  uint32_t [6]:window_retmem_data
*              record verify locked clear_dtu  
*
*		  uint32_t [22]:always mode 
*			   Record always mode status	
************************************************************/

/* the verification will be locked if failed counter is equal to this setting */
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_MAX_COUNTS
#define WINDOW_VERIFY_FAILED_MAX_COUNTS	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_MAX_COUNTS
#else
#define WINDOW_VERIFY_FAILED_MAX_COUNTS	6
#endif

/* expire time of the last failed verification */
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_EXPIRE_TIME_S
#define WINDOW_VERIFY_FAILED_EXPIRE_TIME_S	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_EXPIRE_TIME_S
#else
#define WINDOW_VERIFY_FAILED_EXPIRE_TIME_S	0
#endif

/* an alarm will be played if failed counter is equal to this setting */
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_COUNTS
#define WINDOW_VERIFY_FAILED_ALARM_COUNTS	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_COUNTS
#if (WINDOW_VERIFY_FAILED_ALARM_COUNTS > WINDOW_VERIFY_FAILED_MAX_COUNTS)
#error "VERIFY_FAILED_ALARM_COUNTS should <= WINDOW_VERIFY_FAILED_MAX_COUNTS"
#endif
#else
#define WINDOW_VERIFY_FAILED_ALARM_COUNTS	0
#endif

#if (WINDOW_VERIFY_FAILED_ALARM_COUNTS > 0)
/* play times of the failed alarm */
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES
#define WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES
#else
#define WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES	1
#endif

/* standby timeout after early alarm is played */
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS
#define WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS
#else
#define WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS	5000
#endif
#else
#define WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES	0
#define WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS	0
#endif

/* play times of the locked alarm */
#ifdef GKT_CONFIG_WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES
#define WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES	\
	GKT_CONFIG_WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES
#else
#define WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES	1
#endif

/* verification locked time */
#ifdef GKT_CONFIG_WINDOW_VERIFY_LOCKED_TIME_S
#define WINDOW_VERIFY_LOCKED_TIME_S	\
	GKT_CONFIG_WINDOW_VERIFY_LOCKED_TIME_S
#else
#define WINDOW_VERIFY_LOCKED_TIME_S	(5 * 60)
#endif

#if (WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES > 0) \
	|| (WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES > 0)
#define WINDOW_VERIFY_ALARM_ENABLE	1
#ifdef GKT_CONFIG_WINDOW_VERIFY_ALARM_INTERVAL_MS
#define WINDOW_VERIFY_ALARM_INTERVAL_MS	\
	GKT_CONFIG_WINDOW_VERIFY_ALARM_INTERVAL_MS
#else
#define WINDOW_VERIFY_ALARM_INTERVAL_MS	200
#endif
#else
#define WINDOW_VERIFY_ALARM_ENABLE	0
#define WINDOW_VERIFY_ALARM_INTERVAL_MS	0
#endif

#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)
#ifdef GKT_CONFIG_WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY
#define WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY	\
	GKT_CONFIG_WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY
#else
#define WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY	GKT_KEY_ASTERISK
#endif
#endif

#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE	\
	&& defined(GKT_CONFIG_WINDOW_VERIFY_EXIT_HOTKEY)
#define WINDOW_VERIFY_EXIT_HOTKEY	\
	GKT_CONFIG_WINDOW_VERIFY_EXIT_HOTKEY	/*1U << GKT_KEY_0*/
#else
#define WINDOW_VERIFY_EXIT_HOTKEY	GKT_KEY_0	
#endif

#ifdef GKT_CONFIG_WINDOW_VERIFY_BROADCAST_USER_HOTKEY
#define WINDOW_VERIFY_BROADCAST_USER_HOTKEY	\
	GKT_CONFIG_WINDOW_VERIFY_BROADCAST_USER_HOTKEY
#else
#define WINDOW_VERIFY_BROADCAST_USER_HOTKEY	GKT_KEY_5
#endif

#if defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE)	\
	&& GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE	\
	&& defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_LIGHT)
#define WINDOW_VERIFY_PASSED_KEY_LED_LIGHT	\
	GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_LIGHT
#endif

#if GKT_KEY_LED_FLICKER_ENABLE

#if !defined(GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_DISABLE) \
	|| !GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_DISABLE
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE	1
#ifdef GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_BITS
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_BITS	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_BITS
#else
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_BITS	\
	((1U << GKT_KEY_1) | (1U << GKT_KEY_3) | (1U << GKT_KEY_5) \
		| (1U << GKT_KEY_7) | (1U << GKT_KEY_9) | (1U << GKT_KEY_0))
#endif
#if defined(GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES) \
	&& (GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES > 0)
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES	\
	GKT_CONFIG_WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES
#else
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES	3
#endif
#else
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE	0
#endif

#if defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES) \
	&& (GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES > 0)
#define WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES	\
	GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES
#else
#define WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES	0
#endif

#if !defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE) \
	|| !GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE
#define WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_ENABLE	1
#ifdef GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_BITS
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
static const uint32_t sc_window_verify_passed_key_led_marquee_frame_bits[] = {
	GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_BITS
};
#endif
#else
static const uint32_t sc_window_verify_passed_key_led_marquee_frame_bits[] = {
	1 << GKT_KEY_1, 1 << GKT_KEY_2, 1 << GKT_KEY_3,	
	1 << GKT_KEY_6,	1 << GKT_KEY_9,	1 << GKT_KEY_POUND,
	1 << GKT_KEY_0,	1 << GKT_KEY_ASTERISK,	1 << GKT_KEY_7,
	1 << GKT_KEY_4,	1 << GKT_KEY_5,	1 << GKT_KEY_8
};
#endif
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
static const uint32_t sc_window_verify_passed_key_led_marquee_frame_nums = 
	sizeof(sc_window_verify_passed_key_led_marquee_frame_bits) / sizeof(uint32_t);
#endif
#else
#define WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_ENABLE	0
#endif

#else
#define WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE	0
#define WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_ENABLE	0
#endif

enum {
	WINDOW_VERIFY_ST_NORMAL = 0,
	WINDOW_VERIFY_ST_GETTING_INFO,
	WINDOW_VERIFY_ST_VERIFY_DOING,
	WINDOW_VERIFY_ST_VERIFY_FAILED,
	WINDOW_VERIFY_ST_LOCK_OPENING,
	WINDOW_VERIFY_ST_LOCK_OPENED,
	WINDOW_VERIFY_ST_LOCK_OPEN_FAILED,
	WINDOW_VERIFY_ST_LOCK_CLOSING,
	WINDOW_VERIFY_ST_LOCK_CLOSED,
	WINDOW_VERIFY_ST_ALWAYS_OPEN_ENABLE,
	WINDOW_VERIFY_ST_ALWAYS_OPEN_DISABLE,
	WINDOW_VERIFY_ST_LOCKED,
	WINDOW_VERIFY_ST_CANCEL_DYNPWD,
	WINDOW_VERIFY_ST_MAX
};

enum {
	WINDOW_VERIFY_TIMER_NEXT_STEP = 0,
	WINDOW_VERIFY_TIMER_VOICE_TIMEOUT,
	WINDOW_VERIFY_TIMER_LOCK_TIMEOUT,
	WINDOW_VERIFY_TIMER_LOCK_RETRY,
	WINDOW_VERIFY_TIMER_COUNT_DOWN,
	WINDOW_VERIFY_TIMER_SYSTEM_REBOOT,
	WINDOW_VERIFY_TIMER_LOCK_OPEN_FAILED,
#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
	WINDOW_VERIFY_TIMER_FAIL_LIGHT,
#endif
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
	WINDOW_VERIFY_TIMER_FACE_ID,
#endif

	WINDOW_VERIFY_TIMER_KEY_LED_FLICKER,
	WINDOW_VERIFY_TIMER_MAX
};

#define WINDOW_VERIFY_F_SYSTEM_INITIALIZED	(1U << 0)
#define WINDOW_VERIFY_F_MULTIPLE_USERS_PRESENT	(1U << 1)
#define WINDOW_VERIFY_F_ADMIN_USER_PRESENT	(1U << 2)
#define WINDOW_VERIFY_F_ALL_KEY_LED_ON		(1U << 3)
#define WINDOW_VERIFY_F_FACE_ID_RESTART		(1U << 4)
#define WINDOW_VERIFY_F_TRIGGER_NEXT_STEP	(1U << 5)
#define WINDOW_VERIFY_F_STANDBY_DISABLED	(1U << 6)
#define WINDOW_VERIFY_F_STANDBY_AFTER_EXIT	(1U << 7)

#define WINDOW_VERIFY_F_OPENED_COMMON	(1U << 8)
#define WINDOW_VERIFY_F_OPENED_MARQUEE	(1U << 9)
#define WINDOW_VERIFY_F_OPENED_HOTKEY	(1U << 10)
#define WINDOW_VERIFY_F_OPENED_KRT	(1U << 11)
#define WINDOW_VERIFY_F_OPENED_MASK	\
	(WINDOW_VERIFY_F_OPENED_COMMON | WINDOW_VERIFY_F_OPENED_MARQUEE \
		| WINDOW_VERIFY_F_OPENED_HOTKEY | WINDOW_VERIFY_F_OPENED_KRT)

#define WINDOW_VERIFY_F_FAILED_COMMON	(1U << 16)
#define WINDOW_VERIFY_F_FAILED_LED_FLICKER	(1U << 17)
#define WINDOW_VERIFY_F_FAILED_LED_FLICKER_KRT	(1U << 18)
#define WINDOW_VERIFY_F_FAILED_VOICE	(1U << 19)
#define WINDOW_VERIFY_F_FAILED_ALARM	(1U << 20)
#define WINDOW_VERIFY_F_FAILED_MASK	\
	(WINDOW_VERIFY_F_FAILED_COMMON | WINDOW_VERIFY_F_FAILED_LED_FLICKER \
		| WINDOW_VERIFY_F_FAILED_VOICE | WINDOW_VERIFY_F_FAILED_ALARM)

#define WINDOW_VERIFY_F_LOCKED_SET	(1U << 24)
#define WINDOW_VERIFY_F_LOCKED_COMMON	(1U << 25)
#define WINDOW_VERIFY_F_LOCKED_ALARM	(1U << 26)
#define WINDOW_VERIFY_F_LOCKED_VOICE	(1U << 27)
#define WINDOW_VERIFY_F_LOCKED_MASK	\
	(WINDOW_VERIFY_F_LOCKED_SET | WINDOW_VERIFY_F_LOCKED_COMMON \
		| WINDOW_VERIFY_F_LOCKED_ALARM | WINDOW_VERIFY_F_LOCKED_VOICE)

#define WINDOW_VERIFY_TIMER_F_SET	0x0001
#define WINDOW_VERIFY_TIMER_F_PERIODIC	0x10000
#define WINDOW_VERIFY_TIMER_F_SET_AND_PERIODIC	\
	(WINDOW_VERIFY_TIMER_F_SET | WINDOW_VERIFY_TIMER_F_PERIODIC)

enum {
	WINDOW_VERIFY_RESULT_SUCCESS = 0,
	WINDOW_VERIFY_RESULT_CANCELLED,
	WINDOW_VERIFY_RESULT_FAILED_GETTING_INFO,
	WINDOW_VERIFY_RESULT_FAILED_USER_UNPASS,
	WINDOW_VERIFY_RESULT_FAILED_INVALID_ACCESS_TIME,
	WINDOW_VERIFY_RESULT_MAX
};

#define WINDOW_VERIFY_CD_CANCEL_TIME_S	5

enum {
	WINDOW_VERIFY_CD_CLOSE_LOCK = 0,
	WINDOW_VERIFY_CD_LOCKED_CLEAR,
	WINDOW_VERIFY_CD_CANCEL_DYNPWD,
	WINDOW_VERIFY_CD_MAX
};

#define WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT	1000
#define WINDOW_VERIFY_LOCK_RETRY_INTERVAL	1000
#if defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) && GKT_CONFIG_DOOR_LOCK_AUTOMATIC
#define WINDOW_VERIFY_LOCK_RETRY_MAXTIMES	1
#else
#define WINDOW_VERIFY_LOCK_RETRY_MAXTIMES	3
#endif
#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN) && (GKT_CONFIG_LIGHTING_EFFECT_EN)
#include "gkt_lighting_effect.h"
#define	WINDOW_VERIFY_LIGHT_EFFETC_MAXCNT	5
#endif

enum {
	WIDGET_ID_PWDBOX = 0,
	WIDGET_ID_MAX
};

GKT_WINDOW_WIDGET_DESCS_DEFINE(verify) = {
	[WIDGET_ID_PWDBOX] = GKT_WIDGET_INPUTBOX_DESC(
			GKT_WIDGET_F_KEY_VOICE_BYPASS, GKT_USER_PASSWORD_MINSIZE, 
			GKT_USER_PASSWORD_SCRAMBLE_MAXSIZE)
};

#define WINDOW_VERIFY_VOICE_IDS_MAXSIZE	\
	(GKT_USER_INDEX_DIGITS)
#define WINDOW_VERIFY_CD_BUFF_MAXSIZE	4
#define WINDOW_VERIFY_USER_TYPE_BUFF_MAXSIZE	15
#define WINDOW_VERIFY_USER_ID_BUFF_MAXSIZE	15
struct _window_verify {
	window_verify_attr_u	*attr;

	uint32_t	state;
	uint32_t	flags;
	uint32_t	timer_flags;
	uint32_t	next_step_delay_time_ms;

	uint32_t	unlock_mode;
	uint32_t	user_type;
	uint32_t	user_id_counts;
	uint32_t	user_ids[2];
	uint32_t	result;

	char	user_type_buff[WINDOW_VERIFY_USER_TYPE_BUFF_MAXSIZE + 1];
	char	user_id_buff[WINDOW_VERIFY_USER_ID_BUFF_MAXSIZE + 1];

	uint8_t	fps_id[2];
	uint8_t	card_id[GKT_RFID_ID_MAXSIZE];
	uint32_t	data_size;

	/* count-down */
	uint32_t	cd_type;
	uint32_t	cd_time;
	char	cd_time_buff[WINDOW_VERIFY_CD_BUFF_MAXSIZE];

	int	voice_request_id;
	uint32_t	try_times;

#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
	gkt_lighting_effect_s	lighting_effect;
	uint32_t	lighting_effect_cnt;
#endif

#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
	uint8_t 		*buffer_face_id;
	uint32_t		len_size_face_id;
#endif
	uint32_t	hotkey;
	gkt_voice_meta_id_t	verify_voice_ids[WINDOW_VERIFY_VOICE_IDS_MAXSIZE];
};
struct _window_verify s_window_verify;


static void window_verify_mask(void);
static void window_verify_cd_start(uint32_t type, 
				uint32_t init_time);
static void window_verify_close_lock(void);
static void window_verify_next_step(void);
static void window_verify_next_step_set(void);
static void window_verify_exit(void);

static int window_verify_timer_set(uint32_t timer_id,
				uint32_t interval, uint32_t flags, uint32_t private_data)
{
	int retval;

	s_window_verify.timer_flags |= WINDOW_VERIFY_TIMER_F_SET << timer_id;
	if (flags & GKT_WINDOW_TIMER_F_PERIODIC)
		s_window_verify.timer_flags |= WINDOW_VERIFY_TIMER_F_PERIODIC << timer_id;
	else
		s_window_verify.timer_flags &= ~(WINDOW_VERIFY_TIMER_F_PERIODIC << timer_id);

	retval = gkt_window_timer_set(timer_id, interval, flags, private_data);
	if (retval != GKT_SUCCESS)
		s_window_verify.timer_flags &= ~(WINDOW_VERIFY_TIMER_F_SET_AND_PERIODIC << timer_id);

	return retval;
}
static void window_verify_timer_clear(uint32_t timer_id)
{
	if (s_window_verify.timer_flags & (WINDOW_VERIFY_TIMER_F_SET << timer_id)) {
		s_window_verify.timer_flags &= ~(WINDOW_VERIFY_TIMER_F_SET_AND_PERIODIC << timer_id);
		gkt_window_timer_clear(timer_id);
	}
}

#define WINDOW_VERIFY_VOICE_F_TIMES_MASK	0xffff
#define WINDOW_VERIFY_VOICE_F_FOLLOW	(1U << 16)
#define WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE	(1U << 17)
#define WINDOW_VERIFY_VOICE_F_MUTE_BYPASS	(1U << 18)
static void window_verify_voice_play(uint32_t combined_id, 
				uint32_t flags, uint32_t interval)
{
	gkt_voice_output_playback_attr_s playback_attr;
	uint32_t voice_flags, duration_ms;
	int retval;
	
	window_verify_timer_clear(WINDOW_VERIFY_TIMER_VOICE_TIMEOUT);

	if (s_window_verify.voice_request_id > 0) {
		gkt_window_voice_stop_id(s_window_verify.voice_request_id);
		s_window_verify.voice_request_id = 0;
	}

	voice_flags = 0;
	if (flags & WINDOW_VERIFY_VOICE_F_FOLLOW)
		voice_flags |= GKT_WINDOW_VOICE_F_FOLLOWING;
	if (flags & WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE)
		voice_flags |= GKT_WINDOW_VOICE_F_NOTIFY_END | GKT_WINDOW_VOICE_F_NOTIFY_ERROR;
	if (!(flags & WINDOW_VERIFY_VOICE_F_MUTE_BYPASS))
		voice_flags |= GKT_WINDOW_VOICE_F_MUTE_AFFECTED;
	if ((flags & WINDOW_VERIFY_VOICE_F_TIMES_MASK) > 1) {
		playback_attr.times = flags & WINDOW_VERIFY_VOICE_F_TIMES_MASK;
		playback_attr.interval = interval;
	}
	else {
		playback_attr.times = 1;
		playback_attr.interval = 0;
	}
	retval = gkt_window_voice_play(&s_window_verify.voice_request_id, 
					combined_id, voice_flags, &playback_attr);
	gkt_trace("window_verify: <VOICE> (%d) request_id(%d)\n", retval,
				s_window_verify.voice_request_id);

	if (flags & WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE) {
		if (retval >= GKT_WINDOW_VOICE_ST_PLAYING)
			duration_ms = gkt_window_voice_get_duration_ms(combined_id, &playback_attr) + 200;
		else
			duration_ms = 3000;
		window_verify_timer_set(WINDOW_VERIFY_TIMER_VOICE_TIMEOUT,
				duration_ms, 0, (uint32_t)s_window_verify.voice_request_id);
	}
}
static void window_verify_voice_stop(void)
{
	window_verify_timer_clear(WINDOW_VERIFY_TIMER_VOICE_TIMEOUT);
	gkt_window_voice_stop(0);
	s_window_verify.voice_request_id = 0;
}
static void window_verify_voice_complete(void)
{
	gkt_window_voice_stop_id(s_window_verify.voice_request_id);
	s_window_verify.voice_request_id = 0;

	window_verify_timer_clear(WINDOW_VERIFY_TIMER_VOICE_TIMEOUT);
	window_verify_next_step_set();
}

#if defined(GKT_CONFIG_USER_PASSWORD_DYNAMIC_ENABLE) && GKT_CONFIG_USER_PASSWORD_DYNAMIC_ENABLE
static void window_verify_cancel_dynpwd(void)
{
	s_window_verify.state = WINDOW_VERIFY_ST_CANCEL_DYNPWD;
	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
	s_window_verify.next_step_delay_time_ms = WINDOW_VERIFY_CD_CANCEL_TIME_S * 1000 + 200;
	window_verify_mask();

	gkt_widget_hide_by_id(WIDGET_ID_PWDBOX);

	/* start cancel count-down */
	window_verify_cd_start(WINDOW_VERIFY_CD_CANCEL_DYNPWD, 
		WINDOW_VERIFY_CD_CANCEL_TIME_S);

	/* play voice */
	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(operation_success),
			WINDOW_VERIFY_VOICE_F_FOLLOW | WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE,
			0);
}
#endif

static void window_verify_cd_start(uint32_t type, 
				uint32_t init_time)
{
	gkt_trace("window_verify: <COUNT-DOWN> start - type(%u), time(%u)\n",
			type, init_time);

	s_window_verify.cd_type = type;
	s_window_verify.cd_time = init_time;
	window_verify_timer_set(WINDOW_VERIFY_TIMER_COUNT_DOWN, 
			1000, GKT_WINDOW_TIMER_F_PERIODIC, 0);

}
#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)
static void window_verify_cd_stop(void)
{
	if (s_window_verify.cd_type < WINDOW_VERIFY_CD_MAX) {
		s_window_verify.cd_type = WINDOW_VERIFY_CD_MAX;
		s_window_verify.cd_time = 0;
		window_verify_timer_clear(WINDOW_VERIFY_TIMER_COUNT_DOWN);
	}
}
#endif
static void window_verify_cd_update(void)
{
	if ((s_window_verify.cd_type < WINDOW_VERIFY_CD_MAX)
		&& (s_window_verify.cd_time > 0)) 
	{
		s_window_verify.cd_time--;
		if (s_window_verify.cd_time > 0) {
			gkt_window_timeout_reset();
		}
		else {
			window_verify_timer_clear(WINDOW_VERIFY_TIMER_COUNT_DOWN);

			gkt_trace("window_verify: <COUNT-DOWN> done - type(%u)\n",
					s_window_verify.cd_type);

			if (WINDOW_VERIFY_CD_CANCEL_DYNPWD == s_window_verify.cd_type)
				window_verify_exit();
			else if (WINDOW_VERIFY_CD_CLOSE_LOCK == s_window_verify.cd_type) {
				s_window_verify.cd_type = WINDOW_VERIFY_CD_MAX;
				window_verify_close_lock();
			}
		}
	}
	else
		window_verify_timer_clear(WINDOW_VERIFY_TIMER_COUNT_DOWN);
}

#if defined(GKT_CONFIG_WINDOW_VERIFY_LED_ALL_ON) && GKT_CONFIG_WINDOW_VERIFY_LED_ALL_ON
static void window_verify_all_key_led_on(void)
{
	gkt_trace("window_verify: <ALL_ON> (%u)(%x)\n",
			s_window_verify.state, s_window_verify.flags);

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_ALL_KEY_LED_ON)) {
		gkt_key_led_control(GKT_KEY_LED_CTRL_ALL_ON, 1);
		s_window_verify.flags |= WINDOW_VERIFY_F_ALL_KEY_LED_ON;
	}
}
static void window_verify_all_key_led_off(void)
{
	gkt_trace("window_verify: <ALL_OFF> (%u)(%x)\n",
			s_window_verify.state, s_window_verify.flags);

	if (s_window_verify.flags & WINDOW_VERIFY_F_ALL_KEY_LED_ON) {
		gkt_key_led_control(GKT_KEY_LED_CTRL_ALL_ON, 0);
		s_window_verify.flags &= ~WINDOW_VERIFY_F_ALL_KEY_LED_ON;
	}
}
#else
#define window_verify_all_key_led_on()	do {} while (0)
#define window_verify_all_key_led_off()	do {} while (0)
#endif

static void window_verify_mask(void)
{
#if defined(GKT_CONFIG_DEBUG_ENABLE) && GKT_CONFIG_DEBUG_ENABLE
	gkt_printf("verify_mask: state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);
#endif

	window_verify_all_key_led_on();
	switch (s_window_verify.state) {
		case WINDOW_VERIFY_ST_NORMAL:
			window_common_mask(0);
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
			if((s_window_verify.flags & WINDOW_VERIFY_F_FACE_ID_RESTART)
				&& (g_window_ram_data.face_id_init_state == WINDOW_DATA_FACE_ID_STATE_SET)) 
			{
				gkt_face_id_verify();
			}
#endif
			break;
		case WINDOW_VERIFY_ST_GETTING_INFO:
			if (GKT_USER_TYPE_CARD == s_window_verify.user_type)
				window_common_mask(1U << GKT_EVENT_KEY);
			else
				window_common_mask(0);
			break;
		case WINDOW_VERIFY_ST_LOCK_OPENING:
			window_common_mask_all();
			gkt_event_unmask_single(GKT_EVENT_SYSTEM);
			break;
		default:
			window_common_mask_all();
			break;
	}

#if WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE
	if (s_window_verify.flags & WINDOW_VERIFY_F_FAILED_LED_FLICKER_KRT) {
		//window_common_control_key_real_trim("verify - failed - mask", 1);
		s_window_verify.flags &= ~WINDOW_VERIFY_F_FAILED_LED_FLICKER_KRT;
	}
#endif
	if (s_window_verify.flags & WINDOW_VERIFY_F_OPENED_KRT) {
		//window_common_control_key_real_trim("verify - opened - mask", 1);
		s_window_verify.flags &= ~WINDOW_VERIFY_F_OPENED_KRT;
	}
}

static void window_verify_show_normal(void)
{
	gkt_widget_set_showable_by_id(WIDGET_ID_PWDBOX, 1);
	gkt_widget_show_by_id(WIDGET_ID_PWDBOX);
	gkt_widget_set_focus_by_id(WIDGET_ID_PWDBOX);
}
static void window_verify_normal(void)
{
	gkt_trace("window_verify: NORMAL - state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	s_window_verify.state = WINDOW_VERIFY_ST_NORMAL;
	s_window_verify.flags &= ~(WINDOW_VERIFY_F_FAILED_MASK | WINDOW_VERIFY_F_LOCKED_MASK);
	s_window_verify.user_type = ~0;

	window_verify_mask();
#if defined(GKT_CONFIG_FPS_ENABLE) && GKT_CONFIG_FPS_ENABLE
	gkt_fps_mask_release();
#endif
	window_verify_show_normal();
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE \
	&& defined(GKT_CONFIG_FACE_ID_POWER_DOMN) && GKT_CONFIG_FACE_ID_POWER_DOMN
		if(g_window_ram_data.face_id_power_state == WINDOW_DATA_FACE_ID_STATE_INIT){
			gkt_face_id_restart();
			g_window_ram_data.face_id_power_state = WINDOW_DATA_FACE_ID_STATE_SET;
		}
		gkt_face_id_wait_ok();
		if(g_window_ram_data.face_id_init_state == WINDOW_DATA_FACE_ID_STATE_SET)
			gkt_face_id_verify();
#endif
}

static void window_verify_show_verifing(void)
{
	gkt_widget_set_showable_by_id(WIDGET_ID_PWDBOX, 0);
	gkt_widget_hide_by_id(WIDGET_ID_PWDBOX);
}

#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
extern uint8_t g_card_calibrate_over;
#define window_verify_wait_rfid_cali_complete()	g_card_calibrate_over
#else
#define window_verify_wait_rfid_cali_complete()	1
#endif
static void window_verify_lock_opened(void)
{
	gkt_trace("window_verify: <OPENED> state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_OPENED_COMMON)) {
		s_window_verify.state = WINDOW_VERIFY_ST_LOCK_OPENED;
		s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP 
				| WINDOW_VERIFY_F_OPENED_COMMON;
		s_window_verify.next_step_delay_time_ms = 0;
		window_verify_mask();
		window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(lock_already_opened), 
				WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
	}
#if WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_ENABLE
	else if (!(s_window_verify.flags & WINDOW_VERIFY_F_OPENED_MARQUEE)) {
		s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP 
				| WINDOW_VERIFY_F_OPENED_MARQUEE;

		if (window_verify_wait_rfid_cali_complete()) {
//			window_common_control_key_real_trim("verify - opened - marquee", 0);
			s_window_verify.flags |= WINDOW_VERIFY_F_OPENED_KRT;

			s_window_verify.next_step_delay_time_ms = 1000;
			gkt_key_led_marquee(sc_window_verify_passed_key_led_marquee_frame_bits,
					sc_window_verify_passed_key_led_marquee_frame_nums, 
					WINDOW_VERIFY_PASSED_KEY_LED_FLICKER_TIMES);
		}
		else
			s_window_verify.next_step_delay_time_ms = 100;
		window_verify_next_step_set();
	}
#endif
	else {	/* !(s_window_verify.flags & WINDOW_VERIFY_F_OPENED_HOTKEY) */
		uint32_t unmask_hotkey_bits = 0;

		s_window_verify.flags |= WINDOW_VERIFY_F_OPENED_HOTKEY;
		s_window_verify.hotkey = ~0;

#ifdef WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY
		if (s_window_verify.flags & WINDOW_VERIFY_F_ADMIN_USER_PRESENT)
			unmask_hotkey_bits |= 1U << WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY;  
#endif
#ifdef WINDOW_VERIFY_BROADCAST_USER_HOTKEY
		unmask_hotkey_bits |= 1U << WINDOW_VERIFY_BROADCAST_USER_HOTKEY;
#endif
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE	\
	&& defined(GKT_CONFIG_WINDOW_VERIFY_EXIT_HOTKEY)
			unmask_hotkey_bits |= WINDOW_VERIFY_EXIT_HOTKEY;
#endif
#if defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE)	\
	&& GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_DISABLE	\
	&& defined(GKT_CONFIG_WINDOW_VERIFY_PASSED_KEY_LED_LIGHT)
			unmask_hotkey_bits |= WINDOW_VERIFY_PASSED_KEY_LED_LIGHT;
#endif

		if (unmask_hotkey_bits) {
			if (!(s_window_verify.flags & WINDOW_VERIFY_F_OPENED_KRT)) {
				//window_common_control_key_real_trim("verify - opened - aon", 0);
				s_window_verify.flags |= WINDOW_VERIFY_F_OPENED_KRT;
			}
			unmask_hotkey_bits |= (1U << GKT_KEY_CANCEL) | (1U << GKT_KEY_OK);
			window_verify_all_key_led_off();
			window_common_mask_except_keys(unmask_hotkey_bits);
		}

		window_verify_cd_start(WINDOW_VERIFY_CD_CLOSE_LOCK, 
				gp_window_data->lock_auto_close_time);
	}
}
static void window_verify_open_lock_failed(void)
{
#if defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) && GKT_CONFIG_DOOR_LOCK_AUTOMATIC
	s_window_verify.state = WINDOW_VERIFY_ST_LOCK_OPEN_FAILED;
	window_verify_timer_set(WINDOW_VERIFY_TIMER_LOCK_OPEN_FAILED,
			2000, 0, 0);
#else
	window_verify_timer_set(WINDOW_VERIFY_TIMER_SYSTEM_REBOOT,
			5000, 0, 0);
#endif
}
static void window_verify_open_lock_do(void)
{
	uint32_t timeout;
	int retval;

	gkt_trace("window_verify: open lock do - %u\n", 
			s_window_verify.try_times);

	if (s_window_verify.try_times < WINDOW_VERIFY_LOCK_RETRY_MAXTIMES) {
		s_window_verify.try_times++;

		retval = gkt_door_lock_open();
		if (GKT_EINPROCESS == retval) {
			timeout = gkt_door_lock_get_timeout(GKT_DOOR_LOCK_OP_OPEN) + 2000;
			window_verify_timer_set(WINDOW_VERIFY_TIMER_LOCK_TIMEOUT,
					timeout, 0, 0);
		}
		else if (GKT_SUCCESS == retval) {
			s_window_verify.flags &= ~WINDOW_VERIFY_F_OPENED_MASK;
			window_verify_lock_opened();
		}
		else if (s_window_verify.try_times < WINDOW_VERIFY_LOCK_RETRY_MAXTIMES) {
			gkt_error("window_verify: open lock request failed %d\n", retval);
			window_verify_timer_set(WINDOW_VERIFY_TIMER_LOCK_RETRY,
					WINDOW_VERIFY_LOCK_RETRY_INTERVAL, 0, 0);
		}
		else
			window_verify_open_lock_failed();
	}
	else
		window_verify_open_lock_failed();

}

#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE
static void window_verify_cancel_remote_unlock(void)
{
	if (g_window_retmem_data.wait_remote_unlock_response) {
		gkt_info("window_verify: cancel remote_unlock \n");
		g_window_retmem_data.wait_remote_unlock_response = 0;
		gkt_network_remote_unlock_request(0);
	}
}
#else
#define window_verify_cancel_remote_unlock()	do {} while (0)
#endif

static void window_verify_open_lock(void)
{
	gkt_trace("window_verify: open lock ... user_id_counts - unlock_mode - user_ids (%u-%u-0x%x)\n",
		s_window_verify.user_id_counts, s_window_verify.unlock_mode, s_window_verify.user_ids);

	s_window_verify.state = WINDOW_VERIFY_ST_LOCK_OPENING;
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
	g_window_ram_data.face_id_verify_suc_state = WINDOW_DATA_FACE_ID_STATE_SET;
#endif

	window_verify_cancel_remote_unlock();
	gkt_window_switch_control(0);
#if defined(GKT_CONFIG_DOOR_KEY_ENABLE) && GKT_CONFIG_DOOR_KEY_ENABLE
	gkt_door_key_mask((1U << GKT_DOOR_KEY_OPEN) | (1U << GKT_DOOR_KEY_DOUBLE_LOCK));
#endif
	gkt_widget_set_showable_by_id(WIDGET_ID_PWDBOX, 0);
	gkt_widget_hide_by_id(WIDGET_ID_PWDBOX);
		
	s_window_verify.flags |= WINDOW_VERIFY_F_STANDBY_DISABLED;
	gkt_window_system_standby_disable();

	s_window_verify.try_times = 0;
	window_verify_open_lock_do();

#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
	s_window_verify.lighting_effect.lighting_effect = GKT_LIGHTING_EFFECT_ON;
	gkt_lighting_effect_display(s_window_verify.lighting_effect);
#endif


#if defined(GKT_CONFIG_AMBIENT_LIGHT_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_ENABLE
#if defined(GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE
	gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_VERIFY_OK, 100, 11);
#else
	gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_VERIFY_OK, 0, 0);
#endif
#endif

	/* add unlock record */
	if ((s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED)
		&& (s_window_verify.user_id_counts > 0))
	{
#if defined(GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE) && GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE
		if ((WINDOW_TRIAL_AUTH_MODE_PERPETUAL != gp_window_unreset_data->trial_auth_mode)
			&& (gp_window_unreset_data->trial_auth_counter < gp_window_unreset_data->trial_auth_count_max))
		{
			gp_window_unreset_data->trial_auth_counter++;
			window_data_save();
		}
#endif
		gkt_record_unlock_add(s_window_verify.user_ids, 
			s_window_verify.user_id_counts);

#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE
		if (gkt_network_is_connected()) {
			gkt_network_unlock_type_e unlock_type;

			if (WINDOW_VERIFY_UNLOCK_MODE_USER == s_window_verify.unlock_mode)
				unlock_type = GKT_NETWORK_UNLOCK_TYPE_VERIFY;
			else if (WINDOW_VERIFY_UNLOCK_MODE_REMOTE == s_window_verify.unlock_mode)
				unlock_type = GKT_NETWORK_UNLOCK_TYPE_REMOTE;
			else
				return;
			gkt_network_unlock_record(unlock_type,
				s_window_verify.user_id_counts, s_window_verify.user_ids);
		}
#endif
	}
}

#if defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) && GKT_CONFIG_DOOR_LOCK_AUTOMATIC \
	&& (GKT_MODULE_LOC_FRONTBOARD == GKT_DOOR_LOCK_LOCATION)
void window_verify_auto_double_close_set_rtc_alarm(void)
{
	int retval;
	uint32_t time_us;
	if ((gp_window_data->lock_auto_double_close_time > WINDOW_LOCK_AUTO_DOUBLE_CLOSE_TIME_MIN)
		&& (gp_window_data->lock_auto_double_close_time <= WINDOW_LOCK_AUTO_DOUBLE_CLOSE_TIME_MAX))
	{
		time_us = gp_window_data->lock_auto_double_close_time * 1000 * 1000;
		retval = gkt_rtc_set_alarm(time_us, 0);
		if (retval != GKT_SUCCESS)
			gkt_error("window_verify: set_rtc_alarm failed, retval(%d)\n", retval);
		else {
			gkt_info("window_verify: set_rtc_alarm success, time_us(%u), read RTC_WITR - 0x%x\n", 
				time_us, gkt_read_reg32(0x40040400 + 0x10));
		}
	}
}
#endif
static void	window_verify_lock_closed(void)
{
	gkt_trace("window_verify: lock closed.\n");

	s_window_verify.state = WINDOW_VERIFY_ST_LOCK_CLOSED;
	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
	s_window_verify.next_step_delay_time_ms = WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT;

	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(lock_already_closed),
			WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
#if defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) && GKT_CONFIG_DOOR_LOCK_AUTOMATIC \
			&& (GKT_MODULE_LOC_FRONTBOARD == GKT_DOOR_LOCK_LOCATION)
	gkt_driver_register_rtc_alarm(window_verify_auto_double_close_set_rtc_alarm);
#endif

	/* let the sliding closure magnet to degauss */
#if defined(GKT_CONFIG_SLIDING_CLOSURE_MAGNET_LEVEL)	
	gkt_sliding_closure_magnet_control(0);
#endif	
}
static void window_verify_close_lock_failed(void)
{
	window_verify_timer_set(WINDOW_VERIFY_TIMER_SYSTEM_REBOOT,
			5000, 0, 0);
}
static void window_verify_close_lock_do(void)
{
	uint32_t timeout;
	int retval;

	gkt_trace("window_verify: close lock do - %u\n", 
			s_window_verify.try_times);

	if (s_window_verify.try_times < WINDOW_VERIFY_LOCK_RETRY_MAXTIMES) {
		s_window_verify.try_times++;

		retval = gkt_door_lock_close(0);
		if (GKT_EINPROCESS == retval) {
			timeout = gkt_door_lock_get_timeout(GKT_DOOR_LOCK_OP_CLOSE) + 1000;
			window_verify_timer_set(WINDOW_VERIFY_TIMER_LOCK_TIMEOUT,
					timeout, 0, 0);
		}
		else if (GKT_SUCCESS == retval)
			window_verify_lock_closed();
		else if (s_window_verify.try_times < WINDOW_VERIFY_LOCK_RETRY_MAXTIMES) {
			gkt_error("window_verify: close lock request failed %d\n", retval);
			window_verify_timer_set(WINDOW_VERIFY_TIMER_LOCK_RETRY,
					WINDOW_VERIFY_LOCK_RETRY_INTERVAL, 0, 0);
		}
		else
			window_verify_close_lock_failed();
	}
	else
		window_verify_close_lock_failed();
}
static void window_verify_close_lock(void)
{
	gkt_trace("window_verify: close lock ...\n");

	gkt_window_switch_control(0);
#if defined(GKT_CONFIG_DOOR_KEY_ENABLE) && GKT_CONFIG_DOOR_KEY_ENABLE
	gkt_door_key_mask((1U << GKT_DOOR_KEY_OPEN) | (1U << GKT_DOOR_KEY_DOUBLE_LOCK));
#endif

	s_window_verify.state = WINDOW_VERIFY_ST_LOCK_CLOSING;
	window_verify_mask();

	s_window_verify.try_times = 0;
	window_verify_close_lock_do();
}

static void window_verify_clear_status(void)
{
	s_window_verify.flags &= ~(WINDOW_VERIFY_F_FAILED_MASK | WINDOW_VERIFY_F_LOCKED_MASK);
	g_window_retmem_data.verify_failed_counts = 0;
	g_window_retmem_data.verify_locked_clear_dtu = 0;

	BPK_WriteKey(&g_window_retmem_data.verify_failed_counts, 1, GKT_RETMEM_WINDOW_VERIFY_FAIL_CNT);
	BPK_WriteKey(&g_window_retmem_data.verify_locked_clear_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_LOCK_CLEAR_DTU);
}
static void window_verify_update_status(void)
{
	gkt_date_time_s dts_current;
	uint32_t dtu_current;
	int retval;

	if ((g_window_retmem_data.verify_failed_counts >= WINDOW_VERIFY_FAILED_MAX_COUNTS)
#if defined(GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE) && GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE
		|| ((WINDOW_TRIAL_AUTH_MODE_PERPETUAL != gp_window_unreset_data->trial_auth_mode)
			&& (gp_window_unreset_data->trial_auth_counter >= gp_window_unreset_data->trial_auth_count_max))
#endif
		)
	{
		if (g_window_retmem_data.verify_locked_clear_dtu > 0) {
			retval = gkt_rtc_get_time(&dts_current);
			if (GKT_SUCCESS == retval) {
				dtu_current = (uint32_t)GKT_DTS_2_DTU(dts_current);
				if (dtu_current < g_window_retmem_data.verify_locked_clear_dtu)
					s_window_verify.flags |= WINDOW_VERIFY_F_LOCKED_SET;
				else
					window_verify_clear_status();
			}
		}
	}
#if (WINDOW_VERIFY_FAILED_EXPIRE_TIME_S > 0)
	else if (g_window_retmem_data.verify_failed_counts > 0) {
		if (g_window_retmem_data.verify_failed_expire_dtu > 0) {
			retval = gkt_rtc_get_time(&dts_current);
			if (GKT_SUCCESS== retval) {
				dtu_current = GKT_DTS_2_DTU(dts_current);
				if (g_window_retmem_data.verify_failed_expire_dtu <= dtu_current)
					window_verify_clear_status();
			}
		}
	}
#endif
}


#if WINDOW_VERIFY_ALARM_ENABLE
static void window_verify_alarm(uint32_t play_times)
{
	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
	s_window_verify.next_step_delay_time_ms = 0;
	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(alarm), 
		WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE | WINDOW_VERIFY_VOICE_F_MUTE_BYPASS 
		| (play_times & WINDOW_VERIFY_VOICE_F_TIMES_MASK), 
		WINDOW_VERIFY_ALARM_INTERVAL_MS);
}
#endif
#if GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE
static void window_verify_trial_locked(void)
{
	gkt_info("window_verify: LOCKED - state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP | WINDOW_VERIFY_F_LOCKED_VOICE;
	s_window_verify.next_step_delay_time_ms = WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT;
	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(verify_already_locked),
			WINDOW_VERIFY_VOICE_F_FOLLOW | WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
}
#endif
static void window_verify_locked(void)
{
	gkt_date_time_s dts_current, dts_clear;
	uint32_t clear_time;	/* default */
	int retval;

	gkt_trace("window_verify: LOCKED - state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_LOCKED_COMMON)) {
		s_window_verify.state = WINDOW_VERIFY_ST_LOCKED;
		s_window_verify.flags |= WINDOW_VERIFY_F_LOCKED_COMMON;

		window_verify_mask();

		clear_time = 0;
		retval = gkt_rtc_get_time(&dts_current);
		if (GKT_SUCCESS == retval) {
			gkt_trace("window_verify: LOCKED - current (%04u-%02u-%02u)(%02u-%02u-%02u)\n",
					dts_current.date.year, dts_current.date.month,
					dts_current.date.day, dts_current.time.hour,
					dts_current.time.minute, dts_current.time.second);

			if (!g_window_retmem_data.verify_locked_clear_dtu) {
				clear_time = WINDOW_VERIFY_LOCKED_TIME_S;

				dts_clear.date.u32_value = dts_current.date.u32_value;
				dts_clear.time.u32_value = dts_current.time.u32_value;
				gkt_dt_add_seconds(&dts_clear, clear_time);
				g_window_retmem_data.verify_locked_clear_dtu = GKT_DTS_2_DTU(dts_clear);
				BPK_WriteKey(&g_window_retmem_data.verify_locked_clear_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_LOCK_CLEAR_DTU);
				gkt_trace("window_verify: LOCKED - clear (%04u-%02u-%02u)(%02u:%02u:%02u)\n",
						dts_clear.date.year, dts_clear.date.month, dts_clear.date.day,
						dts_clear.time.hour, dts_clear.time.minute, dts_clear.time.second);
			}
			else {
				GKT_DTU_2_DTS(dts_clear, g_window_retmem_data.verify_locked_clear_dtu);
				gkt_dt_seconds_elapsed_from_base(&dts_clear,
							&dts_current, &clear_time);
			}
		}

		window_verify_cd_start(WINDOW_VERIFY_CD_LOCKED_CLEAR, clear_time);
	}

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_LOCKED_ALARM)) {
		s_window_verify.flags |= WINDOW_VERIFY_F_LOCKED_ALARM;
		window_verify_alarm(WINDOW_VERIFY_LOCKED_ALARM_PLAY_TIMES);
		gkt_trace("window_verify: LOCKED - ALARM ...\n");
	}
	else if (!(s_window_verify.flags & WINDOW_VERIFY_F_LOCKED_VOICE)) {
		s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP | WINDOW_VERIFY_F_LOCKED_VOICE;
		s_window_verify.next_step_delay_time_ms = WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT;
		window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(verify_already_locked),
				WINDOW_VERIFY_VOICE_F_FOLLOW | WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
		gkt_trace("window_verify: LOCKED - VOICE ...\n");
	}
	else {
		if ((WINDOW_VERIFY_CD_LOCKED_CLEAR == s_window_verify.cd_type) 
			&& (s_window_verify.cd_time > 0))
		{
			window_verify_exit();
		}
		else {
			window_verify_clear_status();
			window_verify_normal();
		}
	}
}

#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
static void verify_lighting(void)
{
	uint8_t light_state;
	light_state = (s_window_verify.lighting_effect_cnt % 2);
	s_window_verify.lighting_effect.lighting_effect = (light_state?GKT_LIGHTING_EFFECT_ON:GKT_LIGHTING_EFFECT_OFF);
	gkt_lighting_effect_display(s_window_verify.lighting_effect);
	if(s_window_verify.lighting_effect_cnt <= WINDOW_VERIFY_LIGHT_EFFETC_MAXCNT){
		window_verify_timer_set(WINDOW_VERIFY_TIMER_FAIL_LIGHT,50, 0, 0);	
		s_window_verify.lighting_effect_cnt++;
	}
	else{
		s_window_verify.lighting_effect_cnt = 0;
	}
}
#endif

static void window_verify_failed(void)
{
	gkt_info("window_verify: FAILED - state(%u), flags(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_FAILED_COMMON)) {
		s_window_verify.state = WINDOW_VERIFY_ST_VERIFY_FAILED;
		s_window_verify.flags |= WINDOW_VERIFY_F_FAILED_COMMON;
		window_verify_mask();

#if defined(GKT_CONFIG_AMBIENT_LIGHT_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_ENABLE
#if defined(GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_FLICKER_ENABLE
		gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_VERIFY_FAILED, 100, 11);
#else
		gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_VERIFY_FAILED, 0, 0);
#endif
#endif

		if ((s_window_verify.attr->type != WINDOW_VERIFY_TYPE_GET_ID)
			&& (s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED)
			&& !g_window_retmem_data.always_open_enabled) 
		{
#if (WINDOW_VERIFY_FAILED_EXPIRE_TIME_S > 0)
			gkt_date_time_s dts_current;
			int retval;

			retval = gkt_rtc_get_time(&dts_current);
			if (GKT_SUCCESS == retval) {
				gkt_trace("window_verify: FAILED - time(%02u:%02u:%02u)\n",
						dts_current.time.hour, dts_current.time.minute,
						dts_current.time.second);
				gkt_dt_add_seconds(&dts_current, WINDOW_VERIFY_FAILED_EXPIRE_TIME_S);
				g_window_retmem_data.verify_failed_expire_dtu = 
						GKT_DTS_2_DTU(dts_current);
				BPK_WriteKey(&g_window_retmem_data.verify_failed_expire_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_EXPIRE_DTU);
			}
#endif
			g_window_retmem_data.verify_failed_counts++;
			BPK_WriteKey(&g_window_retmem_data.verify_failed_counts, 1, GKT_RETMEM_WINDOW_VERIFY_FAIL_CNT);
			gkt_info("window_verify: FAILED - counts(%u)\n",
					g_window_retmem_data.verify_failed_counts);
		}

		gkt_widget_hide_by_id(WIDGET_ID_PWDBOX);
		gkt_widget_reset_by_id(WIDGET_ID_PWDBOX);
	}

	if (!(s_window_verify.flags & WINDOW_VERIFY_F_FAILED_VOICE)) {
		s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP 
				| WINDOW_VERIFY_F_FAILED_VOICE;
		s_window_verify.next_step_delay_time_ms = 0;

		gkt_info("window_verify: FAILED - VOICE...\n");
		window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(invalid_user), WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
	}
#if WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE
	else if (!(s_window_verify.flags & WINDOW_VERIFY_F_FAILED_LED_FLICKER)) {
		s_window_verify.flags |= WINDOW_VERIFY_F_FAILED_LED_FLICKER 
				| WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;

#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
		s_window_verify.lighting_effect_cnt = 0;
		verify_lighting();
#endif
		if (window_verify_wait_rfid_cali_complete()) {
//			window_common_control_key_real_trim("verify - failed - flicker", 0);
			s_window_verify.flags |= WINDOW_VERIFY_F_FAILED_LED_FLICKER_KRT;

			gkt_key_led_flicker(WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_BITS,
				WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_TIMES);
			s_window_verify.next_step_delay_time_ms = 800;
		}
		else
			s_window_verify.next_step_delay_time_ms = 100;
		window_verify_next_step_set();
	}
#endif
#if (WINDOW_VERIFY_FAILED_ALARM_COUNTS > 0)
	else if (WINDOW_VERIFY_FAILED_ALARM_COUNTS == g_window_retmem_data.verify_failed_counts) {
		if  (!(s_window_verify.flags & WINDOW_VERIFY_F_FAILED_ALARM)) {
			s_window_verify.flags |= WINDOW_VERIFY_F_FAILED_ALARM;
			window_verify_alarm(WINDOW_VERIFY_FAILED_ALARM_PLAY_TIMES);
#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE
			gkt_network_message_upload(GKT_NETWORK_MESSAGE_TYPE_FAILED_ALARM_ANY);
#endif
			gkt_trace("window_verify: FAILED - ALARM ...\n");
		}
		else {
#if defined(GKT_CONFIG_WDTE_ENABLE) && GKT_CONFIG_WDTE_ENABLE
			gkt_window_timeout_standby(WINDOW_VERIFY_FAILED_ALARM_TO_STANDBY_TIME_MS);
#endif
			window_verify_normal();
		}
	}
#endif
	else if (g_window_retmem_data.verify_failed_counts >= WINDOW_VERIFY_FAILED_MAX_COUNTS) {
		s_window_verify.flags &= ~WINDOW_VERIFY_F_LOCKED_MASK;
		s_window_verify.flags |= WINDOW_VERIFY_F_LOCKED_SET;
		g_window_retmem_data.verify_locked_clear_dtu = 0;
		BPK_WriteKey(&g_window_retmem_data.verify_locked_clear_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_LOCK_CLEAR_DTU);
		window_verify_locked();
#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE
		gkt_network_message_upload(GKT_NETWORK_MESSAGE_TYPE_FREEZE_ANY);
#endif
	}
	else
		window_verify_normal();
}

#ifdef GKT_CONFIG_WINDOW_VERIFY_DEFAULT_PASSWORD
static int window_verify_is_default_password(uint8_t *data, uint32_t len)
{
	uint8_t password_default[] = { GKT_CONFIG_WINDOW_VERIFY_DEFAULT_PASSWORD };
	uint32_t password_default_size = sizeof(password_default) - 1;
	uint32_t i;

	if (len == password_default_size) {
		for (i = 0; i < password_default_size; i++) {
			if (data[i] != password_default[i])
				return 0;
		}
		return 1;
	}
	return 0;
}
#endif

#if defined(GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE) && GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE \
	&& defined(GKT_CONFIG_DOOR_TRIAL_MODE_PERPETUAL_KEY)
static int window_verify_is_trial_mode_perpetual_key(uint8_t *data, uint32_t len)
{
	uint8_t key[] = { GKT_CONFIG_DOOR_TRIAL_MODE_PERPETUAL_KEY };
	uint32_t key_size = sizeof(key) - 1;
	uint32_t i;
 
	if (len == key_size) {
		for (i = 0; i < key_size; i++) {
			if (data[i] != key[i])
				return 0;
		}
 		return 1;
 	}
 	return 0;
 }
#endif
#if defined(GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE) && GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE \
			&& defined(GKT_CONFIG_DOOR_VERIFY_LOCKED_KEY)
static int window_verify_is_verify_locked_key(uint8_t *data, uint32_t len)
{
	uint8_t key[] = { GKT_CONFIG_DOOR_VERIFY_LOCKED_KEY };
	uint32_t key_size = sizeof(key) - 1;
	uint32_t i;

	if (len == key_size) {
		for (i = 0; i < key_size; i++) {
			if (data[i] != key[i])
				return 0;		}
		return 1;
	}
	return 0;
}
#endif

static void window_verify_do(uint32_t user_type,
				const void *data, uint32_t len)
{
	uint32_t authority;
	uint32_t verified_user_id;
	int retval;
#ifdef GKT_CONFIG_WINDOW_VERIFY_DEFAULT_PASSWORD
	int default_pwd;
#endif

	gkt_info("window_verify_do: state(%u), type(%u) len(%u)\n",
		s_window_verify.state, user_type, len);

	if (s_window_verify.state != WINDOW_VERIFY_ST_NORMAL) {
		gkt_error("window_verify_do: invalid state(%u)\n", s_window_verify.state);
		return;
	}

	s_window_verify.state = WINDOW_VERIFY_ST_VERIFY_DOING;
	s_window_verify.user_type = user_type;

	if ((s_window_verify.user_type < GKT_USER_TYPE_MAX)
		&& data && (len > 0))
	{
		window_verify_mask();

#if defined(GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE) && GKT_CONFIG_DOOR_TRIAL_MODE_ENABLE \
	&& defined(GKT_CONFIG_DOOR_TRIAL_MODE_PERPETUAL_KEY)
		if (window_verify_is_trial_mode_perpetual_key((uint8_t *)data, len)) {
			gp_window_unreset_data->trial_auth_mode = WINDOW_TRIAL_AUTH_MODE_TEMPORARY;
			gp_window_unreset_data->trial_auth_counter = 0;
			/* update */
			window_data_save();
			return;
		}
#endif
#if defined(GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE) && GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE \
			&& defined(GKT_CONFIG_DOOR_VERIFY_LOCKED_KEY)
		if (window_verify_is_verify_locked_key((uint8_t *)data, len)) {
			gp_window_unreset_data->verify_locked_status  = !gp_window_unreset_data->verify_locked_status;
			window_data_save();
			window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(operation_success),
					WINDOW_VERIFY_VOICE_F_FOLLOW | WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE, 0);
			return;
		}
#endif

		if (s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED) {
#if defined(GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE) && GKT_CONFIG_DOOR_VERIFY_LOCKED_ENABLE
			gkt_info("window_verify_do verify_locked_status=%d\n", gp_window_unreset_data->verify_locked_status);
			if (gp_window_unreset_data->verify_locked_status) {
				window_verify_trial_locked();
				return;
			}
#endif
			if (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type)
				authority = GKT_USER_AUTH_MAX;
			else if (WINDOW_VERIFY_TYPE_LOGIN == s_window_verify.attr->type)
				authority = GKT_USER_AUTH_ADMIN;
			else
				authority = s_window_verify.attr->get_id.user_auth;

			verified_user_id = (0 == s_window_verify.user_id_counts) ?
				~0 : s_window_verify.user_ids[0];
			retval = gkt_window_user_verify(user_type, authority, 
							data, len, verified_user_id);
			if (GKT_EINPROCESS == retval) {
				s_window_verify.result = WINDOW_VERIFY_RESULT_MAX;
				window_verify_show_verifing();
			}
			else {
				s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_USER_UNPASS;
				window_verify_failed();
			}
		} 
		else {
#ifdef GKT_CONFIG_WINDOW_VERIFY_DEFAULT_PASSWORD
			if (GKT_USER_TYPE_PASSWORD == s_window_verify.user_type) {
				default_pwd = window_verify_is_default_password((uint8_t *)data, len);
				if (!default_pwd) {
					s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_USER_UNPASS;
					window_verify_failed();
					return;
				}
			}
#endif
#if defined(GKT_CONFIG_DOOR_TAMPER_ENABLE) \
				&& GKT_CONFIG_DOOR_TAMPER_ENABLE
			window_door_tamper_stop();
#endif
			window_verify_open_lock();
		}
	}
	else {
		s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_GETTING_INFO;
		window_verify_failed();
	}
}

#if defined(GKT_CONFIG_WINDOW_DUAL_VERIFY_ENABLE) && GKT_CONFIG_WINDOW_DUAL_VERIFY_ENABLE
static void window_verify_another(void)
{
	s_window_verify.state = WINDOW_VERIFY_ST_NORMAL;
	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
	s_window_verify.next_step_delay_time_ms = 0;
	s_window_verify.user_type = ~0;
	
	gkt_widget_reset_by_id(WIDGET_ID_PWDBOX);
	window_verify_show_normal();

	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(please_verify_another_user), 
			WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE | WINDOW_VERIFY_VOICE_F_MUTE_BYPASS,
			0);
}
#endif

#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)
static void window_verify_enable_always_open_mode(void)
{
#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_OPEN_WITH_ADMIN) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_OPEN_WITH_ADMIN
	uint32_t value;
	if (s_window_verify.flags & WINDOW_VERIFY_F_ADMIN_USER_PRESENT) 
#endif
	{
		gkt_trace("window_verify: <ALWAYS_OPEN> open - state(%u), enabled(%d)\n",
				s_window_verify.state, g_window_retmem_data.always_open_enabled);

		s_window_verify.state = WINDOW_VERIFY_ST_ALWAYS_OPEN_ENABLE;
		s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
		s_window_verify.next_step_delay_time_ms =
			WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT;
		window_verify_mask();

		g_window_retmem_data.always_open_enabled = 1;
		value = 1;
		BPK_WriteKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
		gkt_window_system_door_set_always_open_state(1);

		window_verify_cd_stop();

		window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(always_open_mode_open),
				WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE | WINDOW_VERIFY_VOICE_F_MUTE_BYPASS,
				0);
	}
}
static void window_verify_disable_always_open_mode(void)
{
	uint32_t value;
	gkt_trace("window_verify: <ALWAYS_OPEN> close - state(%u), enabled(%d)\n",
			s_window_verify.state, 
			g_window_retmem_data.always_open_enabled);

	s_window_verify.state = WINDOW_VERIFY_ST_ALWAYS_OPEN_DISABLE;
	s_window_verify.flags |= WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
	s_window_verify.next_step_delay_time_ms = WINDOW_VERIFY_NEXT_STEP_DELAY_TIME_DEFAULT;
	window_verify_mask();

	g_window_retmem_data.always_open_enabled = 0;
	value = 0;
	BPK_WriteKey(&value, 1, GKT_RETMEM_ALWAYS_MODE_STATUS);
	gkt_window_system_door_set_always_open_state(0);

	gkt_widget_set_showable_by_id(WIDGET_ID_PWDBOX, 0);
	gkt_widget_hide_by_id(WIDGET_ID_PWDBOX);
	
	window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(always_open_mode_close),
			WINDOW_VERIFY_VOICE_F_WAIT_COMPLETE | WINDOW_VERIFY_VOICE_F_MUTE_BYPASS,
			0);
}
#endif

static void window_verify_exit(void)
{
	if (s_window_verify.flags & WINDOW_VERIFY_F_STANDBY_DISABLED) {
		s_window_verify.flags &= ~WINDOW_VERIFY_F_STANDBY_DISABLED;
		gkt_window_system_standby_enable();
	}

#if defined(GKT_CONFIG_SLIDING_CLOSURE_ENABLE) \
		&& GKT_CONFIG_SLIDING_CLOSURE_ENABLE
	int standby_pending;

	standby_pending = gkt_window_system_is_standby_pending();
	if (!standby_pending)
		gkt_window_exit();
	else
		gkt_window_system_standby(1);
#else
		gkt_window_exit();
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
		if(s_window_verify.user_type == GKT_USER_TYPE_FACE_ID){
			gkt_keypad_peak_control(GKT_KEYPAD_CTRL_ENABLE);
			gkt_key_led_control(GKT_KEY_LED_CTRL_ENABLE, 0);
			g_window_ram_data.face_id_verify_suc_state = WINDOW_DATA_FACE_ID_STATE_SET;
			g_window_ram_data.silent_mode = 1;
			return;
		}
#endif
		if ((s_window_verify.flags & WINDOW_VERIFY_F_STANDBY_AFTER_EXIT)
			|| gp_window_unreset_data->factory_inspect_complete)
		{
			if (s_window_verify.state != WINDOW_VERIFY_ST_LOCK_OPEN_FAILED)
				gkt_window_system_standby(1);
		}
#endif
}



#if !defined(GKT_CONFIG_WINDOW_VOICE_MUTE_DISABLE) \
	|| !GKT_CONFIG_WINDOW_VOICE_MUTE_DISABLE
static void window_verify_key_mute(void)
{
	if (gp_window_data->voice_mute_enable
		&& (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type))
	{
		gkt_key_voice_mask(~0);
	}
}
static void window_verify_key_unmute(void)
{
	if (gp_window_data->voice_mute_enable
		&& (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type))
	{
		gkt_key_voice_mask(0);
	}
}
#else
#define window_verify_key_mute()	do {} while (0)
#define window_verify_key_unmute()	do {} while (0)
#endif

static void window_verify_index_voice(uint32_t user_index)
{
	uint32_t i, user_bit;

	i = GKT_USER_INDEX_DIGITS;
	while (i-- > 0) {
		user_bit = user_index % 10;
		user_index /= 10;
		s_window_verify.verify_voice_ids[i] = gc_window_voice_meta_numbers[GKT_LAGNUAGE][user_bit];
	}
}

static int window_verify_key_event_handler(uint32_t minor_type)
{
	int retval = GKT_EVENT_HANDLE_CONTINUE;
	uint32_t user_index;

	gkt_trace("window_verify: <KEY> state(%u), flags(0x%x), key(%x)\n",
				s_window_verify.state, s_window_verify.flags, 
				minor_type);
	
	if (WINDOW_VERIFY_ST_LOCK_OPENED == s_window_verify.state) {
		if (s_window_verify.flags & WINDOW_VERIFY_F_OPENED_HOTKEY) {
			if (WINDOW_VERIFY_BROADCAST_USER_HOTKEY == minor_type) {
				user_index = GKT_USER_INDEX(s_window_verify.user_ids[s_window_verify.user_id_counts-1]);
				window_verify_index_voice(user_index);
				gkt_window_voice_play_meta(NULL, 
						&s_window_verify.verify_voice_ids[0], 
						WINDOW_VERIFY_VOICE_IDS_MAXSIZE, 
						GKT_WINDOW_VOICE_F_NOTIFY_END | GKT_WINDOW_VOICE_F_NOTIFY_ERROR);
			}
			else if (GKT_KEY_OK == minor_type) {
#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)
			if (WINDOW_VERIFY_ALWAYS_OPEN_HOTKEY == s_window_verify.hotkey)
				window_verify_enable_always_open_mode();
#endif

#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE	\
	&& defined(GKT_CONFIG_WINDOW_VERIFY_EXIT_HOTKEY)
			if (WINDOW_VERIFY_EXIT_HOTKEY == minor_type)
				s_window_verify.flags &= ~WINDOW_VERIFY_F_STANDBY_AFTER_EXIT;
#endif
			}
#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)			
			else if (minor_type < GKT_KEY_MAX)
				s_window_verify.hotkey = minor_type;
#endif			
		}
#if WINDOW_VERIFY_PASSED_KEY_LED_MARQUEE_ENABLE
		else if (s_window_verify.flags & WINDOW_VERIFY_F_OPENED_MARQUEE) {
			if (GKT_KEY_MINOR_LED_FLICKER_END == minor_type) {
				window_verify_timer_clear(WINDOW_VERIFY_TIMER_NEXT_STEP);
				window_verify_lock_opened();
			}
		}
#endif

		retval = GKT_EVENT_HANDLE_COMPLETE;
	}
#if WINDOW_VERIFY_FAILED_KEY_LED_FLICKER_ENABLE
	else if (WINDOW_VERIFY_ST_VERIFY_FAILED == s_window_verify.state) {
		if (GKT_KEY_MINOR_LED_FLICKER_END == minor_type) {
			window_verify_timer_clear(WINDOW_VERIFY_TIMER_NEXT_STEP);
			window_verify_next_step();
			retval = GKT_EVENT_HANDLE_COMPLETE;
		}
	}
#endif

	return retval;
}

static void window_verify_next_step(void)
{
	gkt_trace("window_verify: <NEXT_STEP> (%u)(0x%x)\n",
		s_window_verify.state, s_window_verify.flags);

	if (WINDOW_VERIFY_ST_NORMAL == s_window_verify.state) {
		if (s_window_verify.user_id_counts > 0) {
			window_verify_mask();
#if defined(GKT_CONFIG_FPS_ENABLE) && GKT_CONFIG_FPS_ENABLE
			gkt_fps_mask_release();
#endif
		}
	}
	else if (WINDOW_VERIFY_ST_LOCK_OPENED == s_window_verify.state)
		window_verify_lock_opened();
	else if ((WINDOW_VERIFY_ST_LOCK_CLOSED == s_window_verify.state)
		|| (WINDOW_VERIFY_ST_CANCEL_DYNPWD == s_window_verify.state)
		|| (WINDOW_VERIFY_ST_ALWAYS_OPEN_ENABLE == s_window_verify.state))
	{
		window_verify_exit();
	}
	else if (WINDOW_VERIFY_ST_VERIFY_FAILED == s_window_verify.state) {
		window_verify_timer_clear(WINDOW_VERIFY_TIMER_NEXT_STEP);
		window_verify_failed();
	}
	else if (WINDOW_VERIFY_ST_LOCKED == s_window_verify.state)
		window_verify_locked();
#if !defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC
	else if (WINDOW_VERIFY_ST_ALWAYS_OPEN_DISABLE == s_window_verify.state)
		window_verify_close_lock();
#endif
}
static void window_verify_next_step_set(void)
{
	int retval;

	if (s_window_verify.flags & WINDOW_VERIFY_F_TRIGGER_NEXT_STEP) {
		s_window_verify.flags &= ~WINDOW_VERIFY_F_TRIGGER_NEXT_STEP;
		if (s_window_verify.next_step_delay_time_ms) {
			retval = window_verify_timer_set(WINDOW_VERIFY_TIMER_NEXT_STEP,
						s_window_verify.next_step_delay_time_ms, 0, 0);
			if (GKT_SUCCESS == retval)
				return;
		}

		window_verify_next_step();
	}
}

static void window_verify_timer_event_handler(
				uint32_t timer_id, uint32_t data)
{
	uint32_t mask;

	gkt_trace("window_verify: <TIMER> flags(0x%x), id(%u), data(0x%x)\n",
			s_window_verify.timer_flags, timer_id, data);

	mask = WINDOW_VERIFY_TIMER_F_SET << timer_id;
	if (!(s_window_verify.timer_flags & mask))
		return;
	else {
		mask = WINDOW_VERIFY_TIMER_F_PERIODIC << timer_id;
		if (!(s_window_verify.timer_flags & mask))
			s_window_verify.timer_flags &= ~(WINDOW_VERIFY_TIMER_F_SET << timer_id);
	}

	if (WINDOW_VERIFY_TIMER_NEXT_STEP == timer_id)
		window_verify_next_step();
	else if (WINDOW_VERIFY_TIMER_VOICE_TIMEOUT == timer_id) {
		gkt_trace("window_verify: <TIMER> VT - request_id(%d)\n",
					s_window_verify.voice_request_id);
		if ((uint32_t)s_window_verify.voice_request_id == data)
			window_verify_voice_complete();
	}
	else if (WINDOW_VERIFY_TIMER_LOCK_TIMEOUT == timer_id) {
		uint32_t lock_status;

		gkt_window_timeout_reset();

		lock_status = gkt_door_lock_get_status();
		gkt_info("window_verify: <LOCK_TIMEOUT> %u - %u\n",
			s_window_verify.state, lock_status);

		if (WINDOW_VERIFY_ST_LOCK_OPENING == s_window_verify.state) {
			if (GKT_DOOR_LOCK_ST_OPENED == lock_status) {
				s_window_verify.flags &= ~WINDOW_VERIFY_F_OPENED_MASK;
				window_verify_lock_opened();
			}
			else {	/* if (GKT_DOOR_ST_LOCK_OPENING == lock_status) */
				gkt_door_lock_reset();
				window_verify_open_lock_do();
			}
		}
		else if (WINDOW_VERIFY_ST_LOCK_CLOSING == s_window_verify.state) {
			if (GKT_DOOR_LOCK_ST_CLOSED == lock_status)
				window_verify_lock_closed();
			else {	/* if (GKT_DOOR_ST_LOCK_CLOSING == lock_status) */
				gkt_door_lock_reset();
				window_verify_close_lock_do();
			}
		}
	}
	else if (WINDOW_VERIFY_TIMER_LOCK_RETRY == timer_id) {
		gkt_window_timeout_reset();
		if (WINDOW_VERIFY_ST_LOCK_OPENING == s_window_verify.state) {
			gkt_door_lock_reset();
			window_verify_open_lock_do();
		}
		else if (WINDOW_VERIFY_ST_LOCK_CLOSING == s_window_verify.state) {
			gkt_door_lock_reset();
			window_verify_close_lock_do();
		}
	}
#if	defined(GKT_CONFIG_LIGHTING_EFFECT_EN)&&(GKT_CONFIG_LIGHTING_EFFECT_EN)
	else if (WINDOW_VERIFY_TIMER_FAIL_LIGHT == timer_id){
		verify_lighting();
	}
#endif
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
	else if (WINDOW_VERIFY_TIMER_FACE_ID == timer_id){
		if(g_window_ram_data.face_id_init_state == WINDOW_DATA_FACE_ID_STATE_SET)
			gkt_face_id_verify();
	}
#endif
	else if (WINDOW_VERIFY_TIMER_COUNT_DOWN == timer_id)
		window_verify_cd_update();
	else if (WINDOW_VERIFY_TIMER_SYSTEM_REBOOT == timer_id)
		gkt_system_reset();
	else if (WINDOW_VERIFY_TIMER_LOCK_OPEN_FAILED == timer_id)
		window_verify_exit();

}

static void window_verify_voice_event_handler(uint32_t minor_type, 
				uint32_t request_id)
{
	gkt_trace("window_verify: <VOICE> request_id(%u - %u), event(%u)\n",
				s_window_verify.voice_request_id,
				request_id, minor_type);

	if (s_window_verify.voice_request_id == request_id) {
		if ((GKT_WINDOW_VOICE_EVENT_PLAY_END == minor_type)
			|| (GKT_WINDOW_VOICE_EVENT_PLAY_ERROR == minor_type)
			|| (GKT_WINDOW_VOICE_EVENT_PLAY_TIMEOUT == minor_type))
		{
			window_verify_voice_complete();

			if ((WINDOW_VERIFY_ST_LOCK_OPENED == s_window_verify.state)
				&& (s_window_verify.user_type < GKT_USER_TYPE_MAX)
				&& (s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED))
			{
				gkt_window_user_verify_update(s_window_verify.user_type);
			}
		}
	}
}

static void window_verify_user_event_handler(uint32_t *evt_data)
{
	uint32_t result, user_id, authority;

	result = evt_data[GKT_WINDOW_USER_EVTDATA_RESULT];
	gkt_trace("window_verify: <USER> result(%u)\n", result);
	
	switch (result) {
		case GKT_USER_VERIFY_PASSED:
		case GKT_USER_VERIFY_PASSED_UPDATE:
			user_id = evt_data[GKT_WINDOW_USER_EVTDATA_DATA];
			authority = GKT_USER_AUTH(user_id);
			if (GKT_USER_AUTH_ADMIN == authority)
				s_window_verify.flags |= WINDOW_VERIFY_F_ADMIN_USER_PRESENT;

#if	defined(GKT_CONFIG_PROXIMITY_SENSOR_ENABLE) && (GKT_CONFIG_PROXIMITY_SENSOR_ENABLE)
			if(g_window_retmem_data.pr_power_state == SENSE_PR_POWER_OFF){
				if(gp_window_data->pr_sensor_state != SENSE_SHUTDOWN){
					gkt_pr_sensor_handle();
				}
			}
			g_window_retmem_data.pr_power_state = SENSE_PR_POWER_ON;
			g_window_retmem_data.pr_power_cnt = 0;
			g_window_retmem_data.pr_power_clear_dtu = 0;
#endif
			window_verify_clear_status();
#if defined(GKT_CONFIG_DOOR_TAMPER_ENABLE) && GKT_CONFIG_DOOR_TAMPER_ENABLE			
			window_door_tamper_stop();
#endif
			if (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type) {
				s_window_verify.user_ids[s_window_verify.user_id_counts] = user_id;
				s_window_verify.user_id_counts++;

#if defined(GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE) \
	&& GKT_CONFIG_WINDOW_ALWAYS_OPEN_MODE_ENABLE \
	&& (!defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) || !GKT_CONFIG_DOOR_LOCK_AUTOMATIC)
				if (g_window_retmem_data.always_open_enabled) {
					window_verify_disable_always_open_mode();
					break;
				}
#endif

#if defined(GKT_CONFIG_WINDOW_DUAL_VERIFY_ENABLE) && GKT_CONFIG_WINDOW_DUAL_VERIFY_ENABLE
				if ((authority != GKT_USER_AUTH_TEMPORARY) 
					&& gp_window_data->dual_verify_enable
					&& (s_window_verify.flags & WINDOW_VERIFY_F_MULTIPLE_USERS_PRESENT)) 
				{
#if defined(GKT_CONFIG_AMBIENT_LIGHT_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_ENABLE
					gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_DEFAULT, 0, 0);
#endif				
					if ((s_window_verify.user_id_counts > 1)
						&& (s_window_verify.user_ids[0] == user_id)) 
					{
						s_window_verify.user_id_counts--;
					}
					if (1 == s_window_verify.user_id_counts) {
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
{
						uint32_t type;

						type = GKT_USER_TYPE(user_id);
						if(type == GKT_USER_TYPE_FACE_ID){//face id open the door
							//NO NEED VERIFY AGAIN
						}
						else{
							s_window_verify.flags |= WINDOW_VERIFY_F_FACE_ID_RESTART;
							window_verify_another();
							break;
						}
}
#else
						window_verify_another();
						break;
#endif
					}
				}
#endif				
#if defined(GKT_CONFIG_DOOR_ADMIN_UNLOCK_ENABLE) && GKT_CONFIG_DOOR_ADMIN_UNLOCK_ENABLE
				if (gkt_door_admin_unlock_is_detected()
					&& !(s_window_verify.flags & WINDOW_VERIFY_F_ADMIN_USER_PRESENT))
				{
					s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_USER_UNPASS;
					window_verify_failed();
					if (s_window_verify.user_id_counts > 0)
						s_window_verify.user_id_counts--;
					break;
				}
#endif
				s_window_verify.result = WINDOW_VERIFY_RESULT_SUCCESS;
				window_verify_open_lock();
			}
			else if (WINDOW_VERIFY_TYPE_LOGIN == s_window_verify.attr->type) {
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
				g_window_ram_data.face_id_verify_suc_state = WINDOW_DATA_FACE_ID_STATE_SET;
#endif
				g_window_ram_data.login_admin_user_index = GKT_USER_INDEX(user_id);
				if (WINDOW_VERIFY_LOGIN_ACTION_SHOW_MAIN_MENU == s_window_verify.attr->login.action) {
					window_verify_cancel_remote_unlock();
					gkt_window_show(WINDOW_ID_menu_main, 0);
				}
				gkt_window_exit();
			}
			else {
				s_window_verify.attr->get_id.user_id = user_id;
				gkt_window_exit();
			}
			break;
		case GKT_USER_VERIFY_INVALID_ACCESS_TIME:
			s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_INVALID_ACCESS_TIME;
			window_verify_failed();
			break;
		case GKT_USER_VERIFY_CANCELLED:
			s_window_verify.user_ids[0] = evt_data[GKT_WINDOW_USER_EVTDATA_DATA];
			s_window_verify.user_id_counts = 1;
#if defined(GKT_CONFIG_USER_PASSWORD_DYNAMIC_ENABLE) && GKT_CONFIG_USER_PASSWORD_DYNAMIC_ENABLE
			window_verify_cancel_dynpwd();
#endif
			break;
		case GKT_USER_VERIFY_FAILED:
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
			if(s_window_verify.user_type == GKT_USER_TYPE_FACE_ID) {
				if(WINDOW_VERIFY_TYPE_LOGIN == s_window_verify.attr->type) {
						window_verify_normal();
						break;
				}
				else {
					gkt_face_id_delete(s_window_verify.buffer_face_id);
				}
			}
#endif
#if defined(GKT_CONFIG_FPS_ENABLE) && GKT_CONFIG_FPS_ENABLE
			if(s_window_verify.user_type == GKT_USER_TYPE_FINGERPRINT) {
				if(WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type) {
					uint16_t id_temp;
					id_temp = s_window_verify.fps_id[0]<<8;
					id_temp |= s_window_verify.fps_id[1];
					gkt_fpsensor_deletetemp(id_temp);
				}
			}
#endif	
			s_window_verify.result = WINDOW_VERIFY_RESULT_FAILED_USER_UNPASS;
			window_verify_failed();
			break;
		default:
			break;
	}
}

static int window_verify_lock_event_handler(uint32_t status)
{
	int retval = GKT_EVENT_HANDLE_CONTINUE;

	gkt_trace("window_verify: <LOCK> status(%u)\n", status);

	if (WINDOW_VERIFY_ST_LOCK_OPENING == s_window_verify.state) {
		retval = GKT_EVENT_HANDLE_COMPLETE;
		window_verify_timer_clear(WINDOW_VERIFY_TIMER_LOCK_TIMEOUT);

		if (GKT_DOOR_LOCK_ST_OPENED == status) {
			s_window_verify.flags &= ~WINDOW_VERIFY_F_OPENED_MASK;
			window_verify_lock_opened();
		}
		else if (GKT_DOOR_LOCK_ST_OPEN_FAILED == status) {
			gkt_door_lock_reset();
			window_verify_open_lock_do();
		}
	}
	else if (WINDOW_VERIFY_ST_LOCK_CLOSING == s_window_verify.state) {
		retval = GKT_EVENT_HANDLE_COMPLETE;
		window_verify_timer_clear(WINDOW_VERIFY_TIMER_LOCK_TIMEOUT);

		if (GKT_DOOR_LOCK_ST_CLOSED == status)
			window_verify_lock_closed();
		else if (GKT_DOOR_LOCK_ST_CLOSE_FAILED == status) {
			gkt_door_lock_reset();
			window_verify_close_lock_do();
		}
	}

	return retval;
}

#if GKT_CONFIG_RFID_ENABLE
static void window_verify_get_card_id(uint32_t minor_type, 
				uint32_t *event_data)
{
	gkt_card_info_s *card_info;
	int key_masked;

	s_window_verify.data_size = 0;
	if(minor_type == GKT_CARD_DETECTED) {
		card_info = (gkt_card_info_s *)event_data[0];

		key_masked = gkt_event_is_masked(GKT_EVENT_KEY);
		if (!key_masked)
			gkt_event_mask_single(GKT_EVENT_KEY, GKT_KEY_MASK_F_LED_DETACH);

#if defined(GKT_CONFIG_CARD_HEADER_ENABLE) \
	&& GKT_CONFIG_CARD_HEADER_ENABLE
		if (GKT_RFID_TYPE_14443A == card_info->base.type) {
			if (((card_info->header[0] != 0x54) && (card_info->header[1] != 0x4B)
				&& (card_info->header[2] != 0x57)) 
				|| (GKT_CARD_HEADER_TYPE_ENROLL != card_info->header[4])) 
			{
				return;
			}
		}
#endif

		s_window_verify.data_size = card_info->base.id_len;
		memcpy(s_window_verify.card_id, card_info->base.id, 
					card_info->base.id_len);
	}
}
#endif

#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
int window_verify_face_id_verify(void)
{
	int retval;
	gkt_user_amount_s amount;

	retval = gkt_user_get_amount(&amount, GKT_USER_AUTH_MAX,
					GKT_USER_TYPE_MAX);
	if ((GKT_SUCCESS == retval) && (amount.used_nums > 0)){
		retval = gkt_user_get_amount(&amount, GKT_USER_AUTH_MAX,
						GKT_USER_TYPE_FACE_ID);
		if ((GKT_SUCCESS == retval) && (amount.used_nums > 0))
			g_window_ram_data.face_id_init_state = WINDOW_DATA_FACE_ID_STATE_SET;
		else
			g_window_ram_data.face_id_init_state = WINDOW_DATA_FACE_ID_STATE_INIT;
	}
	else if(GKT_SUCCESS == retval){//no user enrolled
		gkt_face_id_demomode(GKT_FACE_ID_DEMOMODE_ENABLE);
		g_window_ram_data.face_id_demomode_state = WINDOW_DATA_FACE_ID_STATE_SET;
		g_window_ram_data.face_id_init_state = WINDOW_DATA_FACE_ID_STATE_SET;
	}

	if (g_window_ram_data.face_id_verify_suc_state == WINDOW_DATA_FACE_ID_STATE_INIT){
		if(g_window_ram_data.face_id_init_state == WINDOW_DATA_FACE_ID_STATE_SET){
			gkt_face_id_verify();
			return GKT_SUCCESS;
		}
	}
	return GKT_ENORESOURCE;
}

static void window_verify_do_face_id(uint32_t user_type,
				const void *data, uint32_t len)
{
	uint32_t authority;
	int retval;

	gkt_info("window_verify_do: state(%u), type(%u) len(%u)\n",
		s_window_verify.state, user_type, len);

	if (s_window_verify.state != WINDOW_VERIFY_ST_NORMAL) {
		gkt_error("window_verify_do: invalid state(%u)\n", s_window_verify.state);
		return;
	}

	if (data && (len > 0)) {
		if (s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED) {
			if (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type)
				authority = GKT_USER_AUTH_MAX;
			else if (WINDOW_VERIFY_TYPE_LOGIN == s_window_verify.attr->type)
				authority = GKT_USER_AUTH_ADMIN;
			else
				authority = s_window_verify.attr->get_id.user_auth;

			retval = gkt_window_user_verify(user_type, authority, data, len, ~0);
			if (GKT_EINPROCESS == retval) {
				s_window_verify.result = WINDOW_VERIFY_RESULT_MAX;
				s_window_verify.state = WINDOW_VERIFY_ST_VERIFY_DOING;
				s_window_verify.user_type = user_type;
			}
		}
	}
}

static void verify_face_id_reply_handle(uint32_t data)
{
	int retval;

	s_window_verify.len_size_face_id = 0;
	retval = gkt_face_id_get_id((uint32_t *)data,
					&s_window_verify.buffer_face_id,
					&s_window_verify.len_size_face_id);
	if (GKT_SUCCESS == retval) {
		if(g_window_ram_data.face_id_demomode_state == WINDOW_DATA_FACE_ID_STATE_SET){
			s_window_verify.user_type = GKT_USER_TYPE_FACE_ID;
			window_door_tamper_stop();
			window_verify_open_lock();
		}
		else{
			window_verify_do_face_id(GKT_USER_TYPE_FACE_ID,
					s_window_verify.buffer_face_id,
					s_window_verify.len_size_face_id);
		}
	}
}

static void verify_face_id_note_handle(uint32_t data)
{
	//voice
	gkt_info("__face_id_ note voice\n");
}

static void window_verify_face_id_handle(uint32_t data)
{
	uint32_t reply_type;
	uint32_t *event_data;

	event_data = (uint32_t *)data;
	reply_type = gkt_face_id_get_reply_type(event_data[GKT_WINDOW_USER_EVTDATA_DATA],MID_VERIFY);
	switch(reply_type){
		case	GKT_FACE_ID_REPLY:
			verify_face_id_reply_handle(data);
		break;
		case	GKT_FACE_ID_NOTE:
			verify_face_id_note_handle(data);
		break;
		case	GKT_FACE_ID_READY_REPLY:
			window_verify_face_id_verify();
		break;
		default:

		break;
	}
}
#endif
#if defined(GKT_CONFIG_BACKBOARD_ENABLE) && GKT_CONFIG_BACKBOARD_ENABLE
static void window_verify_unlock_special(uint32_t unlock_mode,
				uint32_t user_id)
{
	gkt_info("window_verify: unlock_special - mode(%u), user_id(0x%x)\n",
			unlock_mode, user_id);

	s_window_verify.unlock_mode = unlock_mode;
	s_window_verify.user_type = GKT_USER_TYPE_MAX;
	if (WINDOW_VERIFY_UNLOCK_MODE_REMOTE == unlock_mode) {
		s_window_verify.user_ids[0] = GKT_USER_ID_BUILD_FULL(
				GKT_USER_AUTH_MAX, 0, GKT_USER_TYPE_SPECIAL,
				GKT_USER_TYPE_SPECIAL_REMOTE, user_id & 0xffff);
		s_window_verify.user_id_counts = 1;
	}
	else
		s_window_verify.user_id_counts = 0;

	window_verify_clear_status();
	window_door_tamper_stop();
	window_verify_open_lock();
}
#endif
extern uint8_t *fps_buffer_global;
static int window_verify_event_handler(
				uint32_t major_type, uint32_t minor_type,
				uint32_t id, uint32_t data)
{
	gkt_event_s event;
	gkt_widget_inputbox_data_s *p_data;
	int evt_result = GKT_EVENT_HANDLE_CONTINUE;
	int retval;
	gkt_user_amount_s amount;

	gkt_trace("window_verify: state(%u), flags(x%x) event(%u - %u)\n",
				s_window_verify.state, s_window_verify.flags,
				major_type, minor_type);

	switch (major_type) {
		case GKT_EVENT_WINDOW:
			if (GKT_WINDOW_INIT == minor_type) {
				s_window_verify.attr = (window_verify_attr_u *)data;
				if (!s_window_verify.attr 
					|| (s_window_verify.attr->type >= WINDOW_VERIFY_TYPE_MAX))
				{
					gkt_error("window_verify: window data invalid!\n");
					return GKT_EPARAM;
				}

				gkt_info("window_verify: <INIT> %u\n", s_window_verify.attr->type);

				s_window_verify.state = WINDOW_VERIFY_ST_NORMAL;
				s_window_verify.flags = 0;
#if defined(GKT_CONFIG_DOOR_LOCK_AUTOMATIC) && GKT_CONFIG_DOOR_LOCK_AUTOMATIC
				s_window_verify.flags |= WINDOW_VERIFY_F_STANDBY_AFTER_EXIT;
#endif
				s_window_verify.timer_flags = 0;
				if (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type)
					s_window_verify.unlock_mode = s_window_verify.attr->unlock.mode;
				s_window_verify.user_type = GKT_USER_TYPE_MAX;
				s_window_verify.user_id_counts = 0;

				BPK_ReadKey(&g_window_retmem_data.verify_failed_counts, 1, GKT_RETMEM_WINDOW_VERIFY_FAIL_CNT);
				BPK_ReadKey(&g_window_retmem_data.verify_failed_expire_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_EXPIRE_DTU);
				BPK_ReadKey(&g_window_retmem_data.verify_locked_clear_dtu, 1, GKT_RETMEM_WINDOW_VERIFY_LOCK_CLEAR_DTU);
				/* system init / user enrolled? */
				retval = gkt_user_get_amount(&amount, GKT_USER_AUTH_MAX,
								GKT_USER_TYPE_MAX);
				if ((GKT_SUCCESS == retval) && (amount.used_nums > 0)) {
					s_window_verify.flags |= WINDOW_VERIFY_F_SYSTEM_INITIALIZED;
					if (amount.used_nums > 1)
						s_window_verify.flags |= WINDOW_VERIFY_F_MULTIPLE_USERS_PRESENT;
				}

				window_verify_update_status();
				if (!(s_window_verify.flags & WINDOW_VERIFY_F_LOCKED_SET)
					&& (WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type)) 
				{
					if (WINDOW_VERIFY_UNLOCK_MODE_USER == s_window_verify.attr->unlock.mode) {
						if (GKT_USER_TYPE_FINGERPRINT == s_window_verify.attr->unlock.user_type) {
							event.window_id = WINDOW_ID_verify;
							event.major_type = GKT_EVENT_FPS;
							event.minor_type = 0;
							event.data[0] = 0;
							gkt_event_stage(&event);
						}
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
						else if (GKT_USER_TYPE_CARD == s_window_verify.attr->unlock.user_type) {
							event.window_id = WINDOW_ID_verify;
							event.major_type = GKT_EVENT_CARD;
							event.minor_type = GKT_CARD_DETECTED;
							event.data[0] = s_window_verify.attr->unlock.extend_data;
							gkt_event_stage(&event);
						}
#endif
					}
				}
			}
			else if (GKT_WINDOW_UNINIT == minor_type) {
				s_window_verify.user_type = GKT_USER_TYPE_MAX;
				s_window_verify.state = WINDOW_VERIFY_ST_NORMAL;

#if defined(GKT_CONFIG_DOOR_KEY_ENABLE) && GKT_CONFIG_DOOR_KEY_ENABLE
				gkt_door_key_mask(0);
#endif
#if defined(GKT_CONFIG_AMBIENT_LIGHT_ENABLE) && GKT_CONFIG_AMBIENT_LIGHT_ENABLE
				gkt_ambient_light_set_state(WINDOW_AMBIENT_LIGHT_STATE_DEFAULT, 0, 0);
#endif
			}
			else if (GKT_WINDOW_ACTIVE == minor_type) {
				window_verify_all_key_led_on();
				window_verify_key_mute();

				if (s_window_verify.flags & WINDOW_VERIFY_F_LOCKED_SET)
					window_verify_locked();
				else {
					if ((WINDOW_VERIFY_TYPE_UNLOCK == s_window_verify.attr->type)
						&& (s_window_verify.attr->unlock.user_type != GKT_USER_TYPE_PASSWORD))
					{
						s_window_verify.user_type = s_window_verify.attr->unlock.user_type;
					}
					else if (WINDOW_VERIFY_TYPE_LOGIN == s_window_verify.attr->type){
						gkt_window_set_voice(WINDOW_VOICE_COMBINED_ID(please_verify_admin_user), 0);
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
						window_verify_timer_set(WINDOW_VERIFY_TIMER_FACE_ID,
							2000, 0, 0);//in case verify too fast
#endif
					}
					else if (WINDOW_VERIFY_TYPE_GET_ID == s_window_verify.attr->type) {
						s_window_verify.attr->get_id.user_id = 0;
						gkt_window_set_voice(WINDOW_VOICE_COMBINED_ID(please_verify_user), 0);
					}

					if(s_window_verify.user_type < GKT_USER_TYPE_MAX)
						window_verify_show_verifing();
					else
						window_verify_normal();
				}
			}
			else if (GKT_WINDOW_INACTIVE == minor_type) {
				window_verify_all_key_led_off();
				window_verify_key_unmute();
			}
			break;
		case GKT_EVENT_WIDGET:
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			if (GKT_WIDGET_EVENT_CLICK == minor_type) {
				p_data = (gkt_widget_inputbox_data_s *)data;
				window_verify_do(GKT_USER_TYPE_PASSWORD, p_data->data, p_data->size);
			}
			else if (GKT_WIDGET_EVENT_DATA_INSUFFICIENT == minor_type) {
				window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(forbid), 0, 0);
			}
			else if (GKT_WIDGET_EVENT_DATA_FULL == minor_type) {
				window_verify_voice_play(WINDOW_VOICE_COMBINED_ID(forbid), 0, 0);
			}
			else if (GKT_WIDGET_EVENT_DATA_LENGTH == minor_type) {
				s_window_verify.user_type = GKT_USER_TYPE_PASSWORD; 
			}
			else if (GKT_WIDGET_EVENT_DATA_EMPTY == minor_type)
				evt_result = GKT_EVENT_HANDLE_CONTINUE;
			break;
		case GKT_EVENT_KEY:
			evt_result = window_verify_key_event_handler(minor_type);
			break;
		case GKT_EVENT_FPS:
			window_verify_voice_stop();
			if(s_window_verify.attr->unlock.extend_data != 0) {
				s_window_verify.attr->unlock.extend_data = 0;
				retval = GKT_SUCCESS;
			}
			else {
				retval = gkt_fpsensor_capture_image();	
			}

			if(retval == GKT_SUCCESS){
				if (s_window_verify.flags & WINDOW_VERIFY_F_SYSTEM_INITIALIZED) {
					uint16_t match_id;
					retval=gkt_fpsensor_extractfeature(0);
					if(retval == GKT_SUCCESS){
						retval = gkt_fpsensor_identify(&match_id);
						if(retval == GKT_SUCCESS){
							s_window_verify.fps_id[1] = (uint8_t)match_id;
							s_window_verify.fps_id[0] = (uint8_t)(match_id>>8);
						}
					}
				}
			}

			if(retval == GKT_SUCCESS){
				window_verify_do(GKT_USER_TYPE_FINGERPRINT,
					s_window_verify.fps_id,2);
			}
			else{
				window_verify_do(GKT_USER_TYPE_FINGERPRINT,NULL,0);
			}
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			break;
#if defined(GKT_CONFIG_RFID_ENABLE) && GKT_CONFIG_RFID_ENABLE
		case GKT_EVENT_CARD:
			window_verify_get_card_id(minor_type, (uint32_t *)data);
			window_verify_do(GKT_USER_TYPE_CARD, s_window_verify.card_id, 
					s_window_verify.data_size);
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			break;
#endif
#if defined(GKT_CONFIG_FACE_ID_ENABLE) && GKT_CONFIG_FACE_ID_ENABLE
		case GKT_EVENT_FACE_ID:
			if(minor_type == 0){//real event
				window_verify_face_id_handle(data);
			}
			else{//virtual event

			}
			break;
#endif
		case GKT_EVENT_USER:
			if (GKT_WINDOW_USER_VERIFY == minor_type)
				window_verify_user_event_handler((uint32_t *)data);
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			break;
		case GKT_EVENT_SYSTEM:
			if (GKT_WINDOW_SYSTEM_DOOR == minor_type) {
				if (GKT_DOOR_NOTIFY_LOCK_STATUS == id)
					evt_result = window_verify_lock_event_handler(data);
#if defined(GKT_CONFIG_DOOR_KEY_ENABLE) && GKT_CONFIG_DOOR_KEY_ENABLE
				else if (GKT_DOOR_NOTIFY_KEY == id) {
					if (GKT_DOOR_KEY_OPEN == data) {
						window_verify_unlock_special(WINDOW_VERIFY_UNLOCK_MODE_KEY, 0);
						evt_result = GKT_EVENT_HANDLE_COMPLETE;
					}
				}
#endif
			}
#if defined(GKT_CONFIG_NETWORK_ENABLE) && GKT_CONFIG_NETWORK_ENABLE
			else if (GKT_WINDOW_SYSTEM_NETWORK == minor_type) {
				if (GKT_NETWORK_NOTIFY_TYPE_REMOTE_UNLOCK == id) {
					if (g_window_retmem_data.wait_remote_unlock_response)
						window_verify_unlock_special(WINDOW_VERIFY_UNLOCK_MODE_REMOTE, data);
					evt_result = GKT_EVENT_HANDLE_COMPLETE;
				}
			}
#endif
			break;
		case GKT_EVENT_TIMER:
			window_verify_timer_event_handler(minor_type, data);
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			break;
		case GKT_EVENT_VOICE:
			window_verify_voice_event_handler(minor_type, id);
			evt_result = GKT_EVENT_HANDLE_COMPLETE;
			break;
		default:
			break;
	}

	return evt_result;
}
GKT_WINDOW_DESC_DEFINE(verify);

